#include "printers.h"

/****************************************************************************\
* Private Variables/Functions
\****************************************************************************/

typedef enum s_tag_param_type
{
	ILPT_NONE,
	ILPT_I1, ILPT_BR_I1,
	ILPT_U1,
	ILPT_I4, ILPT_BR_I4,
	ILPT_U4,
	ILPT_I8,
	ILPT_R4,
	ILPT_R8,
	ILPT_TOKEN,
	ILPT_I_VEC,  // int vector, for 'switch' only <uint32>, <int32>+
} s_param_type;

typedef struct s_tag_il_table_def
{
	str_wc name;
	s_param_type param_type;
} s_il_table_def;

#define S_IL_DAUL_BYTE_LEAD 0xFE  /* lead a daul-byte instruction */

static s_il_table_def s_il1b_tbl[] =
{
	/* 00 */ { L"nop             ", ILPT_NONE      },
	/* 01 */ { L"break           ", ILPT_NONE      },
	/* 02 */ { L"ldarg.0         ", ILPT_NONE      },
	/* 03 */ { L"ldarg.1         ", ILPT_NONE      },
	/* 04 */ { L"ldarg.2         ", ILPT_NONE      },
	/* 05 */ { L"ldarg.3         ", ILPT_NONE      },
	/* 06 */ { L"ldloc.0         ", ILPT_NONE      },
	/* 07 */ { L"ldloc.1         ", ILPT_NONE      },
	/* 08 */ { L"ldloc.2         ", ILPT_NONE      },
	/* 09 */ { L"ldloc.3         ", ILPT_NONE      },
	/* 0A */ { L"stloc.0         ", ILPT_NONE      },
	/* 0B */ { L"stloc.1         ", ILPT_NONE      },
	/* 0C */ { L"stloc.2         ", ILPT_NONE      },
	/* 0D */ { L"stloc.3         ", ILPT_NONE      },
	/* 0E */ { L"ldarg.s         ", ILPT_U1        },
	/* 0F */ { L"ldarga.s        ", ILPT_U1        },
	/* 10 */ { L"starg.s         ", ILPT_U1        },
	/* 11 */ { L"ldloc.s         ", ILPT_U1        },
	/* 12 */ { L"ldloca.s        ", ILPT_U1        },
	/* 13 */ { L"stloc.s         ", ILPT_U1        },
	/* 14 */ { L"ldnull          ", ILPT_NONE      },
	/* 15 */ { L"ldc.i4.m1       ", ILPT_NONE      },
	/* 16 */ { L"ldc.i4.0        ", ILPT_NONE      },
	/* 17 */ { L"ldc.i4.1        ", ILPT_NONE      },
	/* 18 */ { L"ldc.i4.2        ", ILPT_NONE      },
	/* 19 */ { L"ldc.i4.3        ", ILPT_NONE      },
	/* 1A */ { L"ldc.i4.4        ", ILPT_NONE      },
	/* 1B */ { L"ldc.i4.5        ", ILPT_NONE      },
	/* 1C */ { L"ldc.i4.6        ", ILPT_NONE      },
	/* 1D */ { L"ldc.i4.7        ", ILPT_NONE      },
	/* 1E */ { L"ldc.i4.8        ", ILPT_NONE      },
	/* 1F */ { L"ldc.i4.s        ", ILPT_I1        },
	/* 20 */ { L"ldc.i4          ", ILPT_I4        },
	/* 21 */ { L"ldc.i8          ", ILPT_I8        },
	/* 22 */ { L"ldc.r4          ", ILPT_R4        },
	/* 23 */ { L"ldc.r8          ", ILPT_R8        },
	/* 24 */ { NULL               , ILPT_NONE      },
	/* 25 */ { L"dup             ", ILPT_NONE      },
	/* 26 */ { L"pop             ", ILPT_NONE      },
	/* 27 */ { L"jmp             ", ILPT_TOKEN     },  // <Method>
	/* 28 */ { L"call            ", ILPT_TOKEN     },  // <Method>
	/* 29 */ { L"calli           ", ILPT_TOKEN     },  // <Signature>
	/* 2A */ { L"ret             ", ILPT_NONE      },
	/* 2B */ { L"br.s            ", ILPT_BR_I1     },
	/* 2C */ { L"brfalse.s       ", ILPT_BR_I1     },
	/* 2D */ { L"brtrue.s        ", ILPT_BR_I1     },
	/* 2E */ { L"beq.s           ", ILPT_BR_I1     },
	/* 2F */ { L"bge.s           ", ILPT_BR_I1     },
	/* 30 */ { L"bgt.s           ", ILPT_BR_I1     },
	/* 31 */ { L"ble.s           ", ILPT_BR_I1     },
	/* 32 */ { L"blt.s           ", ILPT_BR_I1     },
	/* 33 */ { L"bne.un.s        ", ILPT_BR_I1     },
	/* 34 */ { L"bge.un.s        ", ILPT_BR_I1     },
	/* 35 */ { L"bgt.un.s        ", ILPT_BR_I1     },
	/* 36 */ { L"ble.un.s        ", ILPT_BR_I1     },
	/* 37 */ { L"blt.un.s        ", ILPT_BR_I1     },
	/* 38 */ { L"br              ", ILPT_BR_I4     },
	/* 39 */ { L"brfalse         ", ILPT_BR_I4     },
	/* 3A */ { L"brtrue          ", ILPT_BR_I4     },
	/* 3B */ { L"beq             ", ILPT_BR_I4     },
	/* 3C */ { L"bge             ", ILPT_BR_I4     },
	/* 3D */ { L"bgt             ", ILPT_BR_I4     },
	/* 3E */ { L"ble             ", ILPT_BR_I4     },
	/* 3F */ { L"blt             ", ILPT_BR_I4     },
	/* 40 */ { L"bne.un          ", ILPT_BR_I4     },
	/* 41 */ { L"bge.un          ", ILPT_BR_I4     },
	/* 42 */ { L"bgt.un          ", ILPT_BR_I4     },
	/* 43 */ { L"ble.un          ", ILPT_BR_I4     },
	/* 44 */ { L"blt.un          ", ILPT_BR_I4     },
	/* 45 */ { L"switch          ", ILPT_I_VEC     },
	/* 46 */ { L"ldind.i1        ", ILPT_NONE      },
	/* 47 */ { L"ldind.u1        ", ILPT_NONE      },
	/* 48 */ { L"ldind.i2        ", ILPT_NONE      },
	/* 49 */ { L"ldind.u2        ", ILPT_NONE      },
	/* 4A */ { L"ldind.i4        ", ILPT_NONE      },
	/* 4B */ { L"ldind.u4        ", ILPT_NONE      },
	/* 4C */ { L"ldind.i8        ", ILPT_NONE      },
	/* 4D */ { L"ldind.i         ", ILPT_NONE      },
	/* 4E */ { L"ldind.r4        ", ILPT_NONE      },
	/* 4F */ { L"ldind.r8        ", ILPT_NONE      },
	/* 50 */ { L"ldind.ref       ", ILPT_NONE      },
	/* 51 */ { L"stind.ref       ", ILPT_NONE      },
	/* 52 */ { L"stind.i1        ", ILPT_NONE      },
	/* 53 */ { L"stind.i2        ", ILPT_NONE      },
	/* 54 */ { L"stind.i4        ", ILPT_NONE      },
	/* 55 */ { L"stind.i8        ", ILPT_NONE      },
	/* 56 */ { L"stind.r4        ", ILPT_NONE      },
	/* 57 */ { L"stind.r8        ", ILPT_NONE      },
	/* 58 */ { L"add             ", ILPT_NONE      },
	/* 59 */ { L"sub             ", ILPT_NONE      },
	/* 5A */ { L"mul             ", ILPT_NONE      },
	/* 5B */ { L"div             ", ILPT_NONE      },
	/* 5C */ { L"div.un          ", ILPT_NONE      },
	/* 5D */ { L"rem             ", ILPT_NONE      },
	/* 5E */ { L"rem.un          ", ILPT_NONE      },
	/* 5F */ { L"and             ", ILPT_NONE      },
	/* 60 */ { L"or              ", ILPT_NONE      },
	/* 61 */ { L"xor             ", ILPT_NONE      },
	/* 62 */ { L"shl             ", ILPT_NONE      },
	/* 63 */ { L"shr             ", ILPT_NONE      },
	/* 64 */ { L"shr.un          ", ILPT_NONE      },
	/* 65 */ { L"neg             ", ILPT_NONE      },
	/* 66 */ { L"not             ", ILPT_NONE      },
	/* 67 */ { L"conv.i1         ", ILPT_NONE      },
	/* 68 */ { L"conv.i2         ", ILPT_NONE      },
	/* 69 */ { L"conv.i4         ", ILPT_NONE      },
	/* 6A */ { L"conv.i8         ", ILPT_NONE      },
	/* 6B */ { L"conv.r4         ", ILPT_NONE      },
	/* 6C */ { L"conv.r8         ", ILPT_NONE      },
	/* 6D */ { L"conv.u4         ", ILPT_NONE      },
	/* 6E */ { L"conv.u8         ", ILPT_NONE      },
	/* 6F */ { L"callvirt        ", ILPT_TOKEN     },  // <Method>
	/* 70 */ { L"cpobj           ", ILPT_TOKEN     },  // <Type>
	/* 71 */ { L"ldobj           ", ILPT_TOKEN     },  // <Type>
	/* 72 */ { L"ldstr           ", ILPT_TOKEN     },  // <String>
	/* 73 */ { L"newobj          ", ILPT_TOKEN     },  // <Method> (.ctor)
	/* 74 */ { L"castclass       ", ILPT_TOKEN     },  // <Type>
	/* 75 */ { L"isinst          ", ILPT_TOKEN     },  // <Type>
	/* 76 */ { L"conv.r.un       ", ILPT_NONE      },
	/* 77 */ { NULL               , ILPT_NONE      },
	/* 78 */ { NULL               , ILPT_NONE      },
	/* 79 */ { L"unbox           ", ILPT_TOKEN     },  // <Type>
	/* 7A */ { L"throw           ", ILPT_NONE      },
	/* 7B */ { L"ldfld           ", ILPT_TOKEN     },  // <Field>
	/* 7C */ { L"ldflda          ", ILPT_TOKEN     },  // <Field>
	/* 7D */ { L"stfld           ", ILPT_TOKEN     },  // <Field>
	/* 7E */ { L"ldsfld          ", ILPT_TOKEN     },  // <Field>
	/* 7F */ { L"ldsflda         ", ILPT_TOKEN     },  // <Field>
	/* 80 */ { L"stsfld          ", ILPT_TOKEN     },  // <Field>
	/* 81 */ { L"stobj           ", ILPT_TOKEN     },  // <Type>
	/* 82 */ { L"conv.ovf.i1.un  ", ILPT_NONE      },
	/* 83 */ { L"conv.ovf.i2.un  ", ILPT_NONE      },
	/* 84 */ { L"conv.ovf.i4.un  ", ILPT_NONE      },
	/* 85 */ { L"conv.ovf.i8.un  ", ILPT_NONE      },
	/* 86 */ { L"conv.ovf.u1.un  ", ILPT_NONE      },
	/* 87 */ { L"conv.ovf.u2.un  ", ILPT_NONE      },
	/* 88 */ { L"conv.ovf.u4.un  ", ILPT_NONE      },
	/* 89 */ { L"conv.ovf.u8.un  ", ILPT_NONE      },
	/* 8A */ { L"conv.ovf.i.un   ", ILPT_NONE      },
	/* 8B */ { L"conv.ovf.u.un   ", ILPT_NONE      },
	/* 8C */ { L"box             ", ILPT_TOKEN     },  // <Type>
	/* 8D */ { L"newarr          ", ILPT_TOKEN     },  // <Type>
	/* 8E */ { L"ldlen           ", ILPT_NONE      },
	/* 8F */ { L"ldelema         ", ILPT_TOKEN     },  // <Type>
	/* 90 */ { L"ldelem.i1       ", ILPT_NONE      },
	/* 91 */ { L"ldelem.u1       ", ILPT_NONE      },
	/* 92 */ { L"ldelem.i2       ", ILPT_NONE      },
	/* 93 */ { L"ldelem.u2       ", ILPT_NONE      },
	/* 94 */ { L"ldelem.i4       ", ILPT_NONE      },
	/* 95 */ { L"ldelem.u4       ", ILPT_NONE      },
	/* 96 */ { L"ldelem.i8       ", ILPT_NONE      },
	/* 97 */ { L"ldelem.i        ", ILPT_NONE      },
	/* 98 */ { L"ldelem.r4       ", ILPT_NONE      },
	/* 99 */ { L"ldelem.r8       ", ILPT_NONE      },
	/* 9A */ { L"ldelem.ref      ", ILPT_NONE      },
	/* 9B */ { L"stelem.i        ", ILPT_NONE      },
	/* 9C */ { L"stelem.i1       ", ILPT_NONE      },
	/* 9D */ { L"stelem.i2       ", ILPT_NONE      },
	/* 9E */ { L"stelem.i4       ", ILPT_NONE      },
	/* 9F */ { L"stelem.i8       ", ILPT_NONE      },
	/* A0 */ { L"stelem.r4       ", ILPT_NONE      },
	/* A1 */ { L"stelem.r8       ", ILPT_NONE      },
	/* A2 */ { L"stelem.ref      ", ILPT_NONE      },
	/* A3 */ { L"ldelem          ", ILPT_TOKEN     },  // <Type>
	/* A4 */ { L"stelem          ", ILPT_TOKEN     },  // <Type>
	/* A5 */ { L"unbox.any       ", ILPT_TOKEN     },  // <Type>
	/* A6 */ { NULL               , ILPT_NONE      },
	/* A7 */ { NULL               , ILPT_NONE      },
	/* A8 */ { NULL               , ILPT_NONE      },
	/* A9 */ { NULL               , ILPT_NONE      },
	/* AA */ { NULL               , ILPT_NONE      },
	/* AB */ { NULL               , ILPT_NONE      },
	/* AC */ { NULL               , ILPT_NONE      },
	/* AD */ { NULL               , ILPT_NONE      },
	/* AE */ { NULL               , ILPT_NONE      },
	/* AF */ { NULL               , ILPT_NONE      },
	/* B0 */ { NULL               , ILPT_NONE      },
	/* B1 */ { NULL               , ILPT_NONE      },
	/* B2 */ { NULL               , ILPT_NONE      },
	/* B3 */ { L"conv.ovf.i1     ", ILPT_NONE      },
	/* B4 */ { L"conv.ovf.u1     ", ILPT_NONE      },
	/* B5 */ { L"conv.ovf.i2     ", ILPT_NONE      },
	/* B6 */ { L"conv.ovf.u2     ", ILPT_NONE      },
	/* B7 */ { L"conv.ovf.i4     ", ILPT_NONE      },
	/* B8 */ { L"conv.ovf.u4     ", ILPT_NONE      },
	/* B9 */ { L"conv.ovf.i8     ", ILPT_NONE      },
	/* BA */ { L"conv.ovf.u8     ", ILPT_NONE      },
	/* BB */ { NULL               , ILPT_NONE      },
	/* BC */ { NULL               , ILPT_NONE      },
	/* BD */ { NULL               , ILPT_NONE      },
	/* BE */ { NULL               , ILPT_NONE      },
	/* BF */ { NULL               , ILPT_NONE      },
	/* C0 */ { NULL               , ILPT_NONE      },
	/* C1 */ { NULL               , ILPT_NONE      },
	/* C2 */ { L"refanyval       ", ILPT_TOKEN     },  // <Type>
	/* C3 */ { L"ckfinite        ", ILPT_NONE      },
	/* C4 */ { NULL               , ILPT_NONE      },
	/* C5 */ { NULL               , ILPT_NONE      },
	/* C6 */ { L"mkrefany        ", ILPT_TOKEN     },  // <Type>
	/* C7 */ { NULL               , ILPT_NONE      },
	/* C8 */ { NULL               , ILPT_NONE      },
	/* C9 */ { NULL               , ILPT_NONE      },
	/* CA */ { NULL               , ILPT_NONE      },
	/* CB */ { NULL               , ILPT_NONE      },
	/* CC */ { NULL               , ILPT_NONE      },
	/* CD */ { NULL               , ILPT_NONE      },
	/* CE */ { NULL               , ILPT_NONE      },
	/* CF */ { NULL               , ILPT_NONE      },
	/* D0 */ { L"ldtoken         ", ILPT_TOKEN     },  // <Type>/<Field>/<Method>
	/* D1 */ { L"conv.u2         ", ILPT_NONE      },
	/* D2 */ { L"conv.u1         ", ILPT_NONE      },
	/* D3 */ { L"conv.i          ", ILPT_NONE      },
	/* D4 */ { L"conv.ovf.i      ", ILPT_NONE      },
	/* D5 */ { L"conv.ovf.u      ", ILPT_NONE      },
	/* D6 */ { L"add.ovf         ", ILPT_NONE      },
	/* D7 */ { L"add.ovf.un      ", ILPT_NONE      },
	/* D8 */ { L"mul.ovf         ", ILPT_NONE      },
	/* D9 */ { L"mul.ovf.un      ", ILPT_NONE      },
	/* DA */ { L"sub.ovf         ", ILPT_NONE      },
	/* DB */ { L"sub.ovf.un      ", ILPT_NONE      },
	/* DC */ { L"endfinally      ", ILPT_NONE      },
	/* DD */ { L"leave           ", ILPT_BR_I4     },
	/* DE */ { L"leave.s         ", ILPT_BR_I1     },
	/* DF */ { L"stind.i         ", ILPT_NONE      },
	/* E0 */ { L"conv.u          ", ILPT_NONE      },
};
#define S_MAX_IL1B 0xE0

static s_il_table_def s_il2b_tbl[] =
{
	/* 00 */ { L"arglist         ", ILPT_NONE      },
	/* 01 */ { L"ceq             ", ILPT_NONE      },
	/* 02 */ { L"cgt             ", ILPT_NONE      },
	/* 03 */ { L"cgt.un          ", ILPT_NONE      },
	/* 04 */ { L"clt             ", ILPT_NONE      },
	/* 05 */ { L"clt.un          ", ILPT_NONE      },
	/* 06 */ { L"ldftn           ", ILPT_TOKEN     },  // <Method>
	/* 07 */ { L"ldvirtftn       ", ILPT_TOKEN     },  // <Method>
	/* 08 */ { NULL               , ILPT_NONE      },
	/* 09 */ { L"ldarg           ", ILPT_U4        },
	/* 0A */ { L"ldarga          ", ILPT_U4        },
	/* 0B */ { L"starg           ", ILPT_U4        },
	/* 0C */ { L"ldloc           ", ILPT_U4        },
	/* 0D */ { L"ldloca          ", ILPT_U4        },
	/* 0E */ { L"stloc           ", ILPT_U4        },
	/* 0F */ { L"localloc        ", ILPT_NONE      },
	/* 10 */ { NULL               , ILPT_NONE      },
	/* 11 */ { L"endfilter       ", ILPT_NONE      },
	/* 12 */ { L"unaligned.      ", ILPT_U1        },
	/* 13 */ { L"volatile.       ", ILPT_NONE      },
	/* 14 */ { L"tail.           ", ILPT_NONE      },
	/* 15 */ { L"initobj         ", ILPT_TOKEN     },  // <Type>
	/* 16 */ { L"constrained.    ", ILPT_TOKEN     },  // <Type>
	/* 17 */ { L"cpblk           ", ILPT_NONE      },
	/* 18 */ { L"initblk         ", ILPT_NONE      },
	/* 19 */ { L"no.             ", ILPT_NONE      },  // ECMA only.
	/* 1A */ { L"rethrow         ", ILPT_NONE      },
	/* 1B */ { NULL               , ILPT_NONE      },
	/* 1C */ { L"sizeof          ", ILPT_TOKEN     },  // <Type>
	/* 1D */ { L"refanytype      ", ILPT_NONE      },
	/* 1E */ { L"readonly.       ", ILPT_NONE      },
};
#define S_MAX_IL2B 0x1E

/****************************************************************************\
* Public Functions
\****************************************************************************/

void print_il_stream(byte *p_il, size_t len)
{
	// Format:
	//     IL_00000000: /* FE XX | XX XX XX XX */ opcode     XXXh (999999999)
	//     IL_00000002: /* XX    |             */ opcode     
	//     IL_000000XX: /* XX    | XX          */ opcode     Xh (99)
	//     IL_000000XX: /* XX    | XX XX XX XX XX XX XX XX */
	//                                            opcode     XXXXXXXXXh (999999999999)
	//     IL_00000000: /* 45    | XX XX XX XX */ switch     XXh (244)
	//                  /*       | XX XX XX XX */            XXh (999, IL_xxxxxxxx)
	//                  /*       | XX XX XX XX */            XXh (999, IL_xxxxxxxx)
	//                  /*       | XX XX XX XX */            XXh (999, IL_xxxxxxxx)

	size_t offset = 0;
	byte op_code;
	s_il_table_def *p_il_def;
	BOOL valid_op_code;
	wchar_t token_str[METADATA_TOKEN_STR_LEN + 1];
	union
	{
		i1 val_I1;
		u1 val_U1;
		i4 val_I4;
		u4 val_U4;
		i8 val_I8;
		r4 val_R4;
		r8 val_R8;
		u4 val_TOKEN;
	} param_val;

	while(offset < len)
	{
		op_code = *p_il;
		wprintf(L"    IL_%08X: /* %02X ", offset, op_code);

		if(op_code == S_IL_DAUL_BYTE_LEAD)
		{
			// 2-byte op code
			++offset; ++p_il;
			op_code = *p_il;

			valid_op_code = op_code <= S_MAX_IL2B;
			p_il_def = s_il2b_tbl + op_code;
			wprintf(L"%02X", op_code);
		}
		else
		{
			// 1-byte op code
			valid_op_code = op_code <= S_MAX_IL1B;
			p_il_def = s_il1b_tbl + op_code;
			wprintf(L"  ");
		}

		wprintf(L" | ");

		++offset; ++p_il;
		if(valid_op_code && p_il_def->name)
		{
			switch(p_il_def->param_type)
			{
			case ILPT_I1:
			case ILPT_BR_I1:
				wprintf(L"%02X          */ ", p_il[0]);
				wprintf(p_il_def->name);
				param_val.val_I1 = (i1)*((i1 *)p_il);
				if(p_il_def->param_type == ILPT_BR_I1)
					wprintf(L"%02Xh (%4d, IL_%08X)",
						param_val.val_I1, param_val.val_I1,
						offset + 1 + param_val.val_I1);
				else
					wprintf(L"%Xh (%d)", param_val.val_I1, param_val.val_I1);
				p_il += 1; offset += 1;
				break;
			case ILPT_U1:
				wprintf(L"%02X          */ ", p_il[0]);
				wprintf(p_il_def->name);
				param_val.val_U1 = (u1)*((u1 *)p_il);
				wprintf(L"%Xh (%d)", param_val.val_U1, param_val.val_U1);
				p_il += 1; offset += 1;
				break;
			case ILPT_I4:
			case ILPT_BR_I4:
				wprintf(L"%02X %02X %02X %02X */ ", p_il[0], p_il[1], p_il[2], p_il[3]);
				wprintf(p_il_def->name);
				param_val.val_I4 = (i4)*((i4 *)p_il);
				if(p_il_def->param_type == ILPT_BR_I4)
					wprintf(L"%08Xh (%11d, IL_%08X)",
						param_val.val_I4, param_val.val_I4,
						offset + 4 + param_val.val_I4);
				else
					wprintf(L"%Xh (%d)", param_val.val_I4, param_val.val_I4);
				p_il += 4; offset += 4;
				break;
			case ILPT_U4:
				wprintf(L"%02X %02X %02X %02X */ ", p_il[0], p_il[1], p_il[2], p_il[3]);
				wprintf(p_il_def->name);
				param_val.val_U4 = (u4)*((u4 *)p_il);
				wprintf(L"%Xh (%d)", param_val.val_U4, param_val.val_U4);
				p_il += 4; offset += 4;
				break;
			case ILPT_I8:
				wprintf(L"%02X %02X %02X %02X %02X %02X %02X %02X */\n"
					L"                                           ",
					p_il[0], p_il[1], p_il[2], p_il[3], p_il[4], p_il[5], p_il[6], p_il[7]);
				wprintf(p_il_def->name);
				param_val.val_I8 = (i8)*((i8 *)p_il);
				wprintf(L"%llXh (%lld)", param_val.val_I8, param_val.val_I8);
				p_il += 8; offset += 8;
				break;
			case ILPT_R4:
				wprintf(L"%02X %02X %02X %02X */ ", p_il[0], p_il[1], p_il[2], p_il[3]);
				wprintf(p_il_def->name);
				param_val.val_R4 = (r4)*((r4 *)p_il);
				wprintf(L"%Xh (%f)", param_val.val_R4, param_val.val_R4);
				p_il += 4; offset += 4;
				break;
			case ILPT_R8:
				wprintf(L"%02X %02X %02X %02X %02X %02X %02X %02X */\n"
					L"                                           ",
					p_il[0], p_il[1], p_il[2], p_il[3], p_il[4], p_il[5], p_il[6], p_il[7]);
				wprintf(p_il_def->name);
				param_val.val_R8 = (r8)*((r8 *)p_il);
				wprintf(L"%llXh (%llf)", param_val.val_R8, param_val.val_R8);
				p_il += 8; offset += 8;
				break;
			case ILPT_TOKEN:
				wprintf(L"%02X %02X %02X %02X */ ", p_il[0], p_il[1], p_il[2], p_il[3]);
				wprintf(p_il_def->name);
				param_val.val_TOKEN = (u4)*((u4 *)p_il);
				format_metadata_token_direct(param_val.val_TOKEN, token_str, METADATA_TOKEN_STR_LEN);
				wprintf(L"%08Xh (%s)", param_val.val_TOKEN, token_str);
				p_il += 4; offset += 4;
				break;
			case ILPT_I_VEC:
			{
				u4 n, i;
				i4 off;
				size_t cur_offset = offset;

				n = (u4)*((u4 *)p_il);
				wprintf(L"%02X %02X %02X %02X */ ", p_il[0], p_il[1], p_il[2], p_il[3]);
				wprintf(p_il_def->name);
				wprintf(L"%Xh (%d)", n, n);
				p_il += 4; offset += 4;

				for(i = 0; i <n; ++i, p_il += 4, offset += 4)
				{
					off = (i4)*((i4 *)p_il);
					wprintf(L"\n                 /*       | %02X %02X %02X %02X */"
						L"                 %08Xh (%11d, IL_%08X)",
						p_il[0], p_il[1], p_il[2], p_il[3], off, off,
						cur_offset + (n + 1) * 4 + off);
				}
			}
			break;
			default:
				wprintf(L"            */ ");
				wprintf(p_il_def->name);
			}
		}
		else
			wprintf(L"<unknown op code>");

		wprintf(L"\n");
	}  // 	while(offset < len)

	if(offset != len)
		wprintf(L"Error: end offset goes beyond the method body.\n");
}
